#include "stdafx.h"
#include "GameState.h"

#include "Input.h"
#include "MusicController.h"
#include "ReplayController.h"
#include "AvatarController.h"
#include "InGameGUIController.h"
#include "Box.h"
#include "StateManager.h"

#include "CommandList.h"

#include "OgreParticleSystemManager.h"
#include "PlasmaBall.h"
#include <Common/Base/hkBase.h>
#include <Physics/Collide/hkpCollide.h>
#include "PhysicsController.h"
#include "PhysicsSystem.h"
#include "Ground.h"

GameState::GameState(std::string ipReceived, bool replay) {
	m_replay = replay;
	m_aCtrl = NULL;
	m_mCtrl = NULL;
	m_camera = NULL;
	ip = ipReceived;
}

GameState::~GameState() {
	delete m_controllers;
	m_controllers = NULL;
}

void GameState::initalize(Ogre::RenderWindow* window) {
	StateManager* sm = StateManager::getInstance();
	Ogre::Root* r = sm->getRoot();
	Ogre::RenderWindow* w = sm->getWindow();
	Ogre::SceneManager* sceneMgr = r->createSceneManager("DefaultSceneManager");

	m_camera = sceneMgr->createCamera("PlayerCam");

	// Look back along -Z
	m_camera->lookAt(Ogre::Vector3(0,0,300));
	m_camera->setNearClipDistance(0.001);
	

	// Create one viewport, entire window
	Ogre::Viewport* vp = w->addViewport(m_camera);
	vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
 
	// Alter the camera aspect ratio to match the viewport
	m_camera->setAspectRatio(
		Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
	
	Model* model = new Model(sceneMgr);
	m_model = model;
	this->setModel(model);

	if (!m_replay) {
		m_networkCtrl = new NetworkController(ip, model);
		this->addController(m_networkCtrl);	
		CommandList::getInstance()->setNetworkController(m_networkCtrl);
		CommandList::getInstance()->setGameState(this);
	}
	
	if (!m_replay) {
		m_aCtrl = new AvatarController(m_networkCtrl);
		this->addController(m_aCtrl);
		m_aCtrl->setModel(model);
	} else if (m_replay) {
		m_rCtrl = new ReplayController(model);
		this->addController(m_rCtrl);
	}

	this->addController(new PhysicsController(model));

	// Create and add the GUI Controller
	m_gCtrl = new InGameGUIController(model, window, "OgreTray", "none");
	this->addController(m_gCtrl);
	

	m_mCtrl = new MusicController(model);
	m_mCtrl->startMusic();
	this->addController(m_mCtrl);
	
	if (!m_replay) {
		m_cCtrl = new SpectatorController(model, window, m_camera);
		this->addController(m_cCtrl);
		m_pCtrl = new Player(m_aCtrl, m_cCtrl, m_mCtrl);
	} else {
		m_cCtrl = new SpectatorController(model, window, m_camera);
		this->addController(m_cCtrl);
	}

	sceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
	
	// Create a light
	//Ogre::Light* l = sceneMgr->createLight("MainLight");
	//l->setPosition(20,80,50);
	
	///////////////////////////////////////////////////// DEMO OBJECTS
	Box* box;
	
	// Box above
	box = new Box(Ogre::Vector3(30,610,0), Ogre::Vector3(10,10,10), false);
	model->addGameObject(box, model->getNextID(), 0,0,0);
	
	// Towers
	box = new Box(Ogre::Vector3(0,140,0), Ogre::Vector3(10,50,10), false);
	model->addGameObject(box, model->getNextID(), 0,0,0);
	box = new Box(Ogre::Vector3(140,0,0), Ogre::Vector3(50,10,10), false);
	model->addGameObject(box, model->getNextID(), 0,0,0);

	//Create sky
	sceneMgr->setSkyBox(true, "Examples/SpaceSkyBox");

	// Create plasma balls
	//add resource locations to make sure that the custom resourses used by plasma ball are usable
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/Materials", "FileSystem", "PlasmaBallResources");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/Particles", "FileSystem", "PlasmaBallResources");
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation("media/Resources/Textures", "FileSystem", "PlasmaBallResources");
	Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("PlasmaBallResources");
		
	// First is the planet with an opaque texture
	PlasmaBall* planet = new PlasmaBall(Ogre::Vector3(0, 0, 0), false, 100, 10, PlasmaBall::TENDRIL_LINE, PlasmaBall::SOLID_GRASS);
	model->addGameObject(planet, model->getNextID());
	
	//The rest are just rolling around
	PlasmaBall* plasmaBall2 = new PlasmaBall( Ogre::Vector3(20, 200, 0), true, 2, 1, PlasmaBall::TENDRIL_LINE );
	model->addGameObject(plasmaBall2, model->getNextID());
	PlasmaBall* plasmaBall3 = new PlasmaBall( Ogre::Vector3(20, 200, 20), true, 3, 1, PlasmaBall::TENDRIL_LINE );
	model->addGameObject(plasmaBall3, model->getNextID());
	PlasmaBall* plasmaBall4 = new PlasmaBall( Ogre::Vector3(-20, 200, 0), true, 4, 1, PlasmaBall::TENDRIL_FORKED );
	model->addGameObject(plasmaBall4, model->getNextID());

	PlasmaBall* plasmaBall5 = new PlasmaBall( Ogre::Vector3(-20, 200, -20), true, 1, 1, PlasmaBall::TENDRIL_LINE );
	model->addGameObject(plasmaBall5, model->getNextID());
	PlasmaBall* plasmaBall6 = new PlasmaBall( Ogre::Vector3(20, 150, 20), true, 5, 1, PlasmaBall::TENDRIL_LINE );
	model->addGameObject(plasmaBall6, model->getNextID());
	PlasmaBall* plasmaBall7 = new PlasmaBall( Ogre::Vector3(0, 210, 0), true, 2, 1, PlasmaBall::TENDRIL_FORKED );
	model->addGameObject(plasmaBall7, model->getNextID());

	PlasmaBall* plasmaBall8 = new PlasmaBall( Ogre::Vector3(120, 200, 0), true, 3, 1, PlasmaBall::TENDRIL_LINE );
	model->addGameObject(plasmaBall8, model->getNextID());
	PlasmaBall* plasmaBall9 = new PlasmaBall( Ogre::Vector3(50, 200, 20), true, 4, 1, PlasmaBall::TENDRIL_LINE );
	model->addGameObject(plasmaBall9, model->getNextID());
	PlasmaBall* plasmaBall10 = new PlasmaBall( Ogre::Vector3(-120, 200, 0), true, 5, 1, PlasmaBall::TENDRIL_FORKED );
	model->addGameObject(plasmaBall10, model->getNextID());
	PlasmaBall* plasmaBall11 = new PlasmaBall( Ogre::Vector3(-50, 200, -40), true, 2, 1, PlasmaBall::TENDRIL_LINE );
	model->addGameObject(plasmaBall11, model->getNextID());
	PlasmaBall* plasmaBall12 = new PlasmaBall( Ogre::Vector3(20, 150, -20), true, 8, 2, PlasmaBall::TENDRIL_LINE );
	model->addGameObject(plasmaBall12, model->getNextID());
	PlasmaBall* plasmaBall13 = new PlasmaBall( Ogre::Vector3(0, 210, 120), true, 3, 1, PlasmaBall::TENDRIL_FORKED );
	model->addGameObject(plasmaBall13, model->getNextID());
	
	Penguin* penguin = new Penguin(Ogre::Vector3(10, 210, 10));
	model->addGameObject(penguin, model->getNextID(), 0, 20, 0);
	penguin->getSceneNode()->scale(2, 2, 2);

	box = new Box(Ogre::Vector3(0,220,0), Ogre::Vector3(2,2,2), true);
	model->addGameObject(box, model->getNextID(), 0,0,0);
}

void GameState::addPlayerAvatar(PlayerAvatar* avatar, bool replay, Ogre::Camera* camera, Model* model) {
	if (m_replay) {
		m_gCtrl->setPlayerAvatar(avatar);
	} else {
		m_aCtrl->setPlayerAvatar(avatar);
		m_gCtrl->setPlayerAvatar(avatar);
	}
	
	m_currentModel->addGameObject(avatar, m_currentModel->getNextID(), 0, 0, 0);
	model->attachCamera(avatar, camera);
	m_mCtrl->setMainAvatar(avatar);
}

AvatarController* GameState::getAvatarController() {
	return m_aCtrl;
}

bool GameState::update(float deltaTime) {
	bool in = State::update(deltaTime);
	if (!m_replay) {
		CommandList::getInstance()->execute(m_model);
	}

	PhysicsSystem::getInstance()->update(deltaTime);

	if (tmp = dynamic_cast<PlayerAvatar*>(m_model->getCameraGameObject())) {
		m_gCtrl->setPlayerAvatar(tmp);
	}

	if(m_camera) {
		Ogre::Vector3 position = m_camera->getDerivedPosition();
		Ogre::Vector3 vectorForward = m_camera->getDerivedOrientation().zAxis();
		Ogre::Vector3 vectorUp = m_camera->getDerivedOrientation().yAxis();

	// Update position of sound listener
	SoundPlayer::getInstance()->update3dListener(position.x, position.y, position.z, 0, 0, 0, 
		vectorForward.x, vectorForward.y, vectorForward.z, vectorUp.x, vectorUp.y, vectorUp.z);
	}

	return in;
}

Model* GameState::getModel() {
	return m_model;
}